/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * $Id: SpeedCtrlServer.hpp,v 1.24 2009-05-13 07:18:19 amaula Exp $
 *
 * \file
 * \brief MaCI - SpeedCtrl Server interface
 * \author Antti Maula <antti.maula@tkk.fi>
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 */
#ifndef _MACI_INTERFACE_SPEEDCTRLSERVER_HPP_
#define _MACI_INTERFACE_SPEEDCTRLSERVER_HPP_
#include "MaCI.hpp"
#include "SpeedCtrlData.hpp"
#include "thread.hpp"
#include "sync.hpp"
#include <list>

// Forward declare gimi::GIMI
namespace gimi {
  class GIMI;
  class GIMIMessage;
}

namespace MaCI {
  namespace SpeedCtrl {

    /** MaCI - SpeedCtrl Server interface
     * 
     * This class contains the methods and types for providing
     * the SpeedCtrl service in the GIMnet.
     */
    class CSpeedCtrlServer : public MaCI::CMaCI, 
                             private gim::CSync,
                             private gim::CThread
    {
    public:
      /** Constructor.
       * 
       * Constructor of the SpeedCtrlServer. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aMaCICtrlServerPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       * used to indicate the instance of devices of same type.
       * @param[in] aDescription User provided description about
       * service. This description will be appended after text
       * 'MaCI-PositionServer; ' in the GIMI service description
       * field.
       */
      CSpeedCtrlServer(MaCICtrl::CMaCICtrlServer *aMaCICtrlServerPtr, 
                       const int aInterfaceMinor,
                       const std::string &aDescription = "");


      /** Destructor.
       */
      ~CSpeedCtrlServer();
 

      /** Open device.
       *
       * Opens the device, basicly registers device to GIMI.
       *  
       * @return                Returns a value of type EMaCIError. 
       *                        
       * \see EMaCIError
       */
      MaCI::EMaCIError DoOpen(void);


      /** Close device.
       *
       * Closes the device. Closes all GIMI registrations and queues.
       *
       * @return                Returns a value of type EMaCIError.
       *
       * \see EMaCIError
       */
      MaCI::EMaCIError DoClose(void);
      


      /** Wait for a Command.
       *
       * This function waits until new command arrives or timeout occurs.
       * If there is unhandled commands since last read, the next
       * in queue is returned (This is because we don't want to
       * drop commands like 'STOP' from the stream) If you want to clear
       * the queue between calls, use ClearCommandBuffer() function.
       *
       * When a command is succesfully returned, the user can inspect
       * the current command through the GetCommand() call of
       * class CSpeedCtrlData. Then, according to command and its
       * specification, additional datafields may be present, they
       * can be queried by similar Get... functions. See the 
       * description of the data encoder/decoder module CSpeedCtrlData.
       *
       * \note This function is not re-entrant, because it has no user
       * provided state-information. If this function is called from
       * multiple functions, it is undefined which thread will really
       * get the command.
       * 
       * \see ClearCommandBuffer()
       * \see CSpeedCtrlData
       * \see MaCI::EMaCIError
       * 
       * @param[out] aData      Reference to SpeedCtrlData. This will
       *                        be filled with incoming command when
       *                        this call is completed succesfully.
       * @param[in] aTimeout_ms Timeout to wait until operation fails
       *                        for timeout.
       * @param[in] aSkipQueued If this value is set to 'true', the
       *                        function will only return the last
       *                        received command and pop older ones
       *                        out from the queue. If this is set to
       *                        'false', all commands are received in
       *                        order. If parameter is undefined, 
       *                        default is 'false'.
       * @return                'KMaCIOK'  when succesfully received
       *                        a new command. KMaCITimeout when operation
       *                        timed out before a command was received.
       *                        Other errors returned when appropriate.
       *                        (See the MaCI::EMaCIError for description)
       */
      MaCI::EMaCIError WaitCommand(CSpeedCtrlData &aData, 
                                   const unsigned int aTimeout_ms,
                                   bool aSkipQueued = false);
      
      
      /** Clear the incoming commands buffer.
       *
       * This functions clears the accumulated command buffer. This
       * function call may be required if the server for some (weird?)
       * reason wants to skip unprocessed commands. Per default the incoming
       * 'Set' commands are all queued until processed. (This ensures
       * that critical commands don't get lost)
       */
      void ClearCommandBuffer(void);

      /** Send a SpeedCtrl interface event. 
       * 
       * All fields present in the provided container will be transmitted.
       * The Event must atleast contain TSpeed-struct and 
       * MaCI::Common::TTimestamp-struct. 
       * (Empty events will not be sent). 
       *
       * \see CSpeedCtrlData
       *
       * @param[in] aData       Reference to CSpeedCtrlData element containing
       *                        atleast the TSpeed-struct.
       * @return                'true' when the element was OK and was 
       *                        succesfully sent to GIMnet. (No guarantees
       *                        are made about reaching any subscriber).
       *                        'false' when the container was broken,
       *                        didn't contain correct elements or there
       *                        was some problem at the GIMnet layer.
       */
      bool SendSpeedEvent(const CSpeedCtrlData &aData);

      /** Sets wanted command sending intervals limits
       * 
       * This function sets wanted command intervals limits. It's for 
       * avoiding client to flood the network. This has meaning especially 
       * when working over slow links like WLAN. SpeedCtrlClient asks these values
       * when opening and take care of limiting command sending speeds. Default values
       * for max command interval is 100 ms and min command interval is 10 ms.
       *
       * @param aMaxCommandInterval_ms    Limit in ms for identical comman packets.
       *                                  They are sent only at maximum interval.
       * @param aMinCommandInterval_ms    Limit in ms for sending command packets.
       *                                  Client ignores SetSpeed-command packets 
       *                                  which are sent 
       *                                
       *
       */
      void SetCommandSendingIntervalsLimits(unsigned int aMaxCommandInterval_ms,
                                            unsigned int aMinCommandInterval_ms);

      /** Sets command timeout time
       * 
       * This function sets timeout time for creating KCommandTimeout-command.  
       * KCommandTimeout-command is created when no command is arrived within 
       * this time and added it's added to the command queue and passed to the
       * user with WaitCommand-function.
       *
       * This is made for safety reason, e.g. when connection between client 
       * and server is lost. 
       *
       * Default value is 200 ms.
       *
       * @param aCommandTimeoutTime_ms    Timeout time in ms
       */
      void SetCommandTimeoutTime(unsigned int aCommandTimeoutTime_ms);

      /** Sets maximum and minimum speed
       * 
       * This fuction sets maximum and minimum speeds that the server can handle. 
       * Client askes them when connecting the server. Minimum speeds are for describing
       * speeds for going backwards if possible. 
       */
      void SetSpeedLimits(float aMaxSpeed, float aMaxAngularSpeed, float aMaxAcceleration,
                          float aMinSpeed, float aMinAngularSpeed, float aMinAcceleration);


    private:
      int ThreadFunction(const int aThreadNumber); ///< Incoming data handler function
      int ProcessMessage(const gimi::GIMIMessage &msg); ///< Incoming data processor function
      unsigned int iMaxCommandInterval_ms;
      unsigned int iMinCommandInterval_ms;
      unsigned int iCommandTimeoutTime_ms;
      bool iClientCommanding;
      TSpeed iMaxSpeeds;
      TSpeed iMinSpeeds;
      std::list<CSpeedCtrlData *> iSpeedCtrlCommandArray; ///< Array of unprocessed commands.

      std::string iServiceDescription; ///< User provided service description field.
    };

  }
}


#endif //_MACI_INTERFACE_SPEEDCTRLSERVER_HPP_
